// 用于存储所有的副作用函数（类似Vue 3中的effect），模拟响应式更新机制
const effects = [];

// 用于存储响应式对象和其属性对应的依赖关系（Set集合），结构为 Map<object, Map<string, Set<function>>>
const targetMap = new Map();

// 模拟Vue 3中的effect，用于创建副作用函数，在函数执行时收集依赖
let activeEffect;

function effect(fn) {
    // console.log('fn',fn);
    const effectFn = () => {
        activeEffect = effectFn;
        fn();
        // 如果新增属性的时候没办法让activeEffect不为null则将activeEffect=null注释
        // 才能正常更新新属性的依赖收集
        // activeEffect = null;
    };
    effectFn();
    return effectFn;
}


// 依赖收集函数，模拟Vue 3中收集依赖的逻辑，将当前的副作用函数添加到对应的数据依赖列表中
function track(target, key) {
    // console.log('track',key,activeEffect);
    if (activeEffect) {
        let depsMap = targetMap.get(target);
        if (!depsMap) {
            depsMap = new Map();
            targetMap.set(target, depsMap);
        }
        let dep = depsMap.get(key);
        if (!dep) {
            dep = new Set();
            depsMap.set(key, dep);
        }
        dep.add(activeEffect);
    }
}

// 触发依赖更新函数，模拟Vue 3中当数据变化时通知依赖更新的逻辑，执行所有收集到的副作用函数
function trigger(target, key) {
    const depsMap = targetMap.get(target);
    // console.log('trigger',depsMap);

    if (depsMap) {
        // console.log('depsMap', depsMap);
        const dep = depsMap.get(key);
        if (dep) {
            dep.forEach(effect => effect());
        }
    }
}
// 创建响应式对象，使用Proxy进行数据劫持
function reactive(obj) {
    return new Proxy(obj, {
        get(target, key, receiver) {
            // 收集依赖（副作用函数）
            // console.log('get');
            track(target, key);
            const value = Reflect.get(target, key, receiver);
            // console.log('value', value);
            if (typeof value === 'object' && value !== null) {
                // 递归处理嵌套对象，确保嵌套结构也是响应式的
                return reactive(value);
            }
            return value;
        },
        set(target, key, value, receiver) {
            // console.log('set');
            // console.log('target', target);
            // console.log('key', key);

            const hadKey = key in target;
            const result = Reflect.set(target, key, value, receiver);
            if (!hadKey) {
                // console.log('如果是新添加的属性，进行依赖收集');
                track(target, key);

                trigger(target, key);
            }

            if (hadKey || (value !== target[key])) {
                // console.log('触发依赖更新执行副作用函数仅当值发生变化或者是新添加属性时触发');
                trigger(target, key);
            }
            return result;
        }
    });
}



// 模拟Vue 3中的渲染函数，将数据渲染到DOM元素上
function render() {
    const inputElement = document.getElementById('inputElement');
    const textElement = document.getElementById('textElement');

    const addBtn = document.getElementById('addBtn');
    const changeBtn = document.getElementById('changeBtn');
    const objElm = document.getElementById('objElm');

    const changeArr = document.getElementById('changeArr');
    const changeIndexArr = document.getElementById('changeIndexArr');
    const arrElm = document.getElementById('arrElm');

    const state = reactive({
        message: 'Initial Message',
        arr: [1, 2, 3, 4, 5],
        obj: {
            name: 'luo',
            year: 27
        }
    });

    // 双向绑定逻辑，给input元素添加input事件监听，更新数据
    inputElement.addEventListener('input', (e) => {
        state.message = e.target.value;
    });

    // 给obj操作的按钮
    addBtn.addEventListener('click', (e) => {
        state.obj.sex = '男'
        state.obj.age = 27
        // obj.name = 'lbf'
        // console.log(state.obj);
    });

    changeBtn.addEventListener('click', (e) => {
        state.obj.name = 'lbf'

        // console.log(state.obj);
    });

    // 给arr操作的按钮

    changeArr.addEventListener('click', (e) => {
        state.arr = [1, 2, 3]
    });

    changeIndexArr.addEventListener('click', (e) => {
        state.arr[0] = 9
        // console.log(state.arr);
    });

    // 读取数据并更新文本元素内容，同时收集依赖
    effect(() => {
        textElement.textContent = state.message;
        objElm.textContent = JSON.stringify(state.obj);
        arrElm.textContent = state.arr;
    });
}

render();
